/**
 * 
 */
package info.niwota.group;

import java.util.ArrayList;

import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.util.Log;
import android.view.View;
import android.view.Window;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.TextView;

/**
 * @author qiangli
 * 
 */
public class VoiceInputActivity extends Activity implements TextWatcher,
		OnClickListener {

	private static final CharSequence KB_COMMA = ",";

	private static final CharSequence KB_LF = "\n";
	
	private static final CharSequence KB_PERIOD = ".";
	
	private static final CharSequence KB_SPACE = " ";
	
	private static final int RC_INPUT = 1;

	private static final String TAG = "VoiceInputActivity";

	private static final String VI_HELP_URI = "file:///android_asset/vi.html";

	private boolean autoediting;

	private CharSequence input;

	private CharSequence oldText;

	private ImageButton redoButton;

	private EditText text;

	private ImageButton undoButton;

	private String newText;

	private int oldStart;

	private int oldEnd;

	private int newStart;

	private int newEnd;

	private TextView title;

	public void afterTextChanged(Editable arg0) {
		if (autoediting) {
			return;
		}
		input = null;
		disableRedoActions();
	}

	private void autoAppendInput() {
		if (TextUtils.isEmpty(input)) {
			return;
		}
		autoediting = true;
		int st = text.getSelectionStart();
		int en = text.getSelectionEnd();
		if (st == -1 || en == -1) {
			text.append(input);
		} else {
			if (st > en) {
				//swap
				int x = st;
				st = en;
				en = x;
			}
			text.getEditableText().replace(st, en, input);
		}
		newText = text.getEditableText().toString();
		newStart = text.getSelectionStart();
		newEnd = text.getSelectionEnd();
		autoediting = false;
		//
		undoButton.setVisibility(View.VISIBLE);
		undoButton.setEnabled(true);
		redoButton.setVisibility(View.GONE);
		redoButton.setEnabled(false);
	}

	private void autoEdit(CharSequence s, int st, int en) {
		autoediting = true;
		//
		text.setText(s);
		if (st < 0 || en < 0 || st > en) {
			st = s.length();
			en = st;
		}
		//
		text.setSelection(st, en);
		//
		autoediting = false;
	}

	public void beforeTextChanged(CharSequence s, int start, int count,
			int after) {
	}

	private void disableRedoActions() {
		redoButton.setVisibility(View.GONE);
		undoButton.setVisibility(View.GONE);
		redoButton.setEnabled(false);
		undoButton.setEnabled(false);
	}

	private void doBS() {
		int st = text.getSelectionStart();
		int en = text.getSelectionEnd();
		if (st < 0 || en <= 0) {
			//en == 0, legitimate but can bs no more
			return;
		}
		st = (st == en ? st - 1 : st);
		//
		if (st > en) {
			//swap
			int x = st;
			st = en;
			en = x;
		}
		text.getEditableText().delete(st, en);
	}

	private void doKB(CharSequence key) {
		int st = text.getSelectionStart();
		int en = text.getSelectionEnd();
		if (st == -1 || en == -1) {
			text.append(key);
		} else {
			if (st > en) {
				//swap
				int x = st;
				st = en;
				en = x;
			}
			text.getEditableText().replace(st, en, key);
		}
	}

	private void doRedo() {
		autoEdit(newText, newStart, newEnd);
		//
		undoButton.setVisibility(View.VISIBLE);
		undoButton.setEnabled(true);
		redoButton.setVisibility(View.GONE);
		redoButton.setEnabled(false);
	}

	private void doSpeak() {
		startVoiceRecognitionActivity();
	}

	private void doUndo() {
		autoEdit(oldText, oldStart, oldEnd);
		//
		undoButton.setVisibility(View.GONE);
		undoButton.setEnabled(false);
		redoButton.setVisibility(View.VISIBLE);
		redoButton.setEnabled(true);
	}

	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data) {
		if (requestCode == RC_INPUT && resultCode == RESULT_OK) {
			ArrayList<String> words = data
					.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
			if (words == null) {
				return;
			}
			int len = words.size();
			if (len == 0) {
				return;
			}
			if (Constants.DEBUG_ENABLED) {
				Log.d(TAG, "words: " + words);
			}
			StringBuilder sb = new StringBuilder();
			for (String w: words) {
				sb.append(w);
				sb.append(KB_SPACE);
			}
			input = normalize(sb);
			oldText = text.getText().toString();
			oldStart = text.getSelectionStart();
			oldEnd = text.getSelectionEnd();
			//
			autoAppendInput();
		}
	}

	private CharSequence normalize(StringBuilder sb) {
		try {
			String[] sa = sb.toString().split("\\s");
			if (sa.length > 0) {
				String p = sa[0];
				int pl = p.length();
				int len = sa.length;
				sb.setLength(0); //reuse sb
				sb.append(p);
				//remove space between single letter words
				for (int i = 1; i < len; i++) {
					String w = sa[i];
					int wl = w.length();
					if (wl > 1 || pl > 1) {
						sb.append(KB_SPACE);
					}
					pl = wl;
					sb.append(w);
				}
				return sb.toString();
			}
		} catch (Exception e) {
			//discard
		}
		return null;
	}

	public void onClick(View v) {
		switch (v.getId()) {
		case R.id.voiceinput_title:
			help();
			return;
		case R.id.voiceinput_speak:
			doSpeak();
			return;
		case R.id.voiceinput_bs:
			doBS();
			return;
		case R.id.voiceinput_comma:
			doKB(KB_COMMA);
			return;
		case R.id.voiceinput_sp:
			doKB(KB_SPACE);
			return;
		case R.id.voiceinput_period:
			doKB(KB_PERIOD);
			return;
		case R.id.voiceinput_lf:
			doKB(KB_LF);
			return;
		case R.id.voiceinput_undo:
			doUndo();
			return;
		case R.id.voiceinput_redo:
			doRedo();
			return;
		case R.id.voiceinput_use:
			Intent data = new Intent();
			data.putExtra(EtalkIntent.EXTRA_INPUT, text.getText().toString());
			setResult(RESULT_OK, data);
			finish();
			break;
		case R.id.voiceinput_discard:
			setResult(RESULT_CANCELED);
			finish();
			break;
		}
	}

	@Override
	public void onCreate(Bundle savedInstanceState) {
		super.onCreate(savedInstanceState);
		//
		setTheme(android.R.style.Theme_Translucent_NoTitleBar);
		requestWindowFeature(Window.FEATURE_NO_TITLE);

		setContentView(R.layout.voiceinput);
		//
		title = (TextView) findViewById(R.id.voiceinput_title);
		text = (EditText) findViewById(R.id.voiceinput_text);
		redoButton = (ImageButton) findViewById(R.id.voiceinput_redo);
		undoButton = (ImageButton) findViewById(R.id.voiceinput_undo);

		Button okButton = (Button) findViewById(R.id.voiceinput_use);
		Button discardButton = (Button) findViewById(R.id.voiceinput_discard);
		//
		View kb = findViewById(R.id.voiceinput_keyboard);
		Button speakButton = (Button) findViewById(R.id.voiceinput_speak);
		Button bsButton = (Button) findViewById(R.id.voiceinput_bs);
		Button commaButton = (Button) findViewById(R.id.voiceinput_comma);
		Button spButton = (Button) findViewById(R.id.voiceinput_sp);
		Button periodButton = (Button) findViewById(R.id.voiceinput_period);
		Button lfButton = (Button) findViewById(R.id.voiceinput_lf);
		//
		okButton.setEnabled(true);
		discardButton.setEnabled(true);

		disableRedoActions();
		//
		boolean canSpeak = Utils.canSpeak(this);
		kb.setVisibility(canSpeak ? View.VISIBLE : View.GONE);
		if (canSpeak) {
			title.setOnClickListener(this); //help
			
			speakButton.setOnClickListener(this);
			bsButton.setOnClickListener(this);
			commaButton.setOnClickListener(this);
			spButton.setOnClickListener(this);
			periodButton.setOnClickListener(this);
			lfButton.setOnClickListener(this);
			
			undoButton.setOnClickListener(this);
			redoButton.setOnClickListener(this);
		} else {
			speakButton.setEnabled(false);
			bsButton.setEnabled(false);
			commaButton.setEnabled(false);
			spButton.setEnabled(false);
			periodButton.setEnabled(false);
			lfButton.setEnabled(false);
			
			redoButton.setEnabled(false);
			undoButton.setEnabled(false);
		}
		okButton.setOnClickListener(this);
		discardButton.setOnClickListener(this);
		//
		text.addTextChangedListener(this);
		//
		autoEdit("", 0, 0);
		//
		input = null;
		Intent i = getIntent();
		init(i);
	}

	private void init(Intent i) {
		if (i == null) {
			return;
		}
		String s = i.getStringExtra(EtalkIntent.EXTRA_INPUT);
		if (!TextUtils.isEmpty(s)) {
			autoEdit(s, -1, -1); // s.length
		}

		String t = i.getStringExtra(EtalkIntent.EXTRA_TITLE);
		if(TextUtils.isEmpty(t)) {
			title.setText(R.string.text_voiceinput);	
		} else {
			title.setText(t);
		}
		//
		String h = i.getStringExtra(EtalkIntent.EXTRA_HINT);
		if (!TextUtils.isEmpty(h)) {
			text.setHint(h);
		}
		
//		int it = i.getIntExtra(EtalkIntent.EXTRA_INPUT_TYPE, -1);
//		if (it != -1) {
//			text.setInputType(it);
//		}
//		int io = i.getIntExtra(EtalkIntent.EXTRA_INPUT_IMEOPTIONS, -1);
//		if (io != -1) {
//			text.setImeOptions(io);
//		}
	}

	public void onTextChanged(CharSequence s, int start, int before, int count) {
	}

	private void startVoiceRecognitionActivity() {
		String ps = getString(R.string.text_voiceinput_prompt_speak);
		Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
		intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL,
				RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
		intent.putExtra(RecognizerIntent.EXTRA_PROMPT, ps);
		startActivityForResult(intent, RC_INPUT);
	}
	
	private void help() {
		try {
			Intent i = new Intent(this, WebViewActivity.class);
			i.setData( Uri.parse(VI_HELP_URI));
			startActivity(i);
		} catch (Exception e) {
			//
		}
	}
}
